﻿using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.CSharp;
using Roslyn.Compilers.CSharp;

namespace WeaverCustomTool
{
    public static class Weaver
    {
        /// <summary>
        /// Weaves the specified code.
        /// </summary>
        /// <param name="code">The code.</param>
        /// <returns></returns>
        public static CodeCompileUnit Weave(string code)
        {
            // Code trees creation
            var weavedCode = new CodeCompileUnit();
            var codeToWeave = SyntaxTree.ParseText(code);
            var rootToWeave = codeToWeave.GetRoot();

            //namespace creation
            var namespacesToImplement = rootToWeave.DescendantNodes().OfType<NamespaceDeclarationSyntax>().ToList();
            foreach (var namespaceDeclaration in namespacesToImplement)
            {
                var weavedNamespace = new NamespaceDeclaration()
                    .FromNamespace(namespaceDeclaration)
                    .MergeImportsWithRoot(rootToWeave);
                weavedCode.Namespaces.Add(weavedNamespace);

                // interface implementation
                var interfacesToImplement = namespaceDeclaration.ChildNodes().OfType<InterfaceDeclarationSyntax>().ToList();
                foreach (var interfaceDeclaration in interfacesToImplement)
                {
                    var weavedType = interfaceDeclaration.Implement();
                    weavedNamespace.Types.Add(weavedType);

                    // property implementations
                    var propertiesToImplement = interfaceDeclaration.Members.OfType<PropertyDeclarationSyntax>().ToList();
                    propertiesToImplement.ForEach(property => property.Weave().InCodeTypeDeclaration(weavedType));
                }   
            }

            return weavedCode;
        }

        public static string GenerateSourceCode(this CodeCompileUnit codeDom)
        {
            // Build source code
            var builder = new StringBuilder();
            using (var writer = new StringWriter(builder))
            {
                new CSharpCodeProvider().GenerateCodeFromCompileUnit(codeDom, writer,
                    new CodeGeneratorOptions
                        {
                        BracingStyle = "C",
                        BlankLinesBetweenMembers = true,
                        IndentString = "    ",
                        VerbatimOrder = false
                    });
            }

            // Return the finalized source code
            return builder.ToString();
        }
    }
}
